package core ;

import java.util.Set ;
import java.util.List ;
import java.util.Map ;
import java.util.ArrayList ;
import org.codehaus.janino.ExpressionEvaluator;


public class Combinator {
    public interface StateHandler {
        public void init() ;
        public boolean refresh(Map<String, Object> bindings) throws Exception ;
    }
    static class ExpressionInfo {
        public ExpressionEvaluator evaluator ;
        public Set<String> params ;
    
        public ExpressionInfo(ExpressionEvaluator evaluator, Set<String> params) {
            this.evaluator = evaluator ;
            this.params = params ;
        }
    }
    public static class WholeAnd implements StateHandler {
        private List<ExpressionInfo> exprs = null ;
        public WholeAnd() {
            this.exprs = new ArrayList<ExpressionInfo>() ;
        }
        public WholeAnd(List<ExpressionInfo> exprs) {
            this.exprs = exprs ;
        }
        public WholeAnd addItem(ExpressionEvaluator evaluator, Set<String> params) {
            exprs.add(new ExpressionInfo(evaluator, params)) ;
            return this ;
        }
        public void init() {
        }
        public boolean refresh(Map<String, Object> bindings) throws Exception {
            for(ExpressionInfo info: exprs) {
                List<Object> args = new ArrayList<Object>() ;
                for(String param: info.params) {
                    args.add(bindings.get(param));
                }
                boolean match = (boolean)info.evaluator.evaluate(args.toArray()) ;
                if (! match) return false ;
            }
            return true ;
        }
    }
    public static class BreakAnd implements StateHandler {
        public void init() {
        }
        public boolean refresh(Map<String, Object> args) {
            return true ;
        }
    }
    public static class RollAnd implements StateHandler {
        private List<ExpressionInfo> exprs = null ;
        private List<Integer> matches = new ArrayList<Integer>() ;

        public RollAnd() {
            exprs = new ArrayList<ExpressionInfo>() ;
        }
        public void init() {
        }
        public RollAnd addItem(ExpressionEvaluator evaluator, Set<String> params) {
            exprs.add(new ExpressionInfo(evaluator, params)) ;
            matches.add(0) ;
            return this ;
        }
        public boolean refresh(Map<String, Object> bindings) throws Exception {
            boolean allCheck = true ;
            for(int i = 0; i < matches.size(); i++) {
                ExpressionInfo info = exprs.get(i) ;
                List<Object> args = new ArrayList<Object>() ;
                for(String param: info.params) {
                    args.add(bindings.get(param));
                }
                boolean currentCheck = (boolean)info.evaluator.evaluate(args.toArray()) ;
                int newMatch = currentCheck ? matches.get(i) + 1: matches.get(i) ;
                if (newMatch == 0) {
                    allCheck = false ;
                }
                matches.set(i, newMatch) ;

                System.out.println(String.format("[debug] %s -> %s", i, newMatch)) ;
            }
            if (!allCheck) return false ;
            
            for(int i =0; i < matches.size(); i++) {
                matches.set(i, matches.get(i) - 1) ;
            }
            return true ;
        }
    }
}
